package server;

import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.lang.reflect.InvocationTargetException;
import java.net.Socket;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.StringTokenizer;

import model.Admin;
import model.AdminImpl;
import model.Cliente;
import model.ClienteImpl;
import model.Libri;
import model.LibriImpl;
import model.Prestiti;
import model.PrestitiImpl;
import utilities.BibliotecaJDBC;
import utilities.EmailSend;
import utilities.RandomPassword;

import com.mysql.jdbc.exceptions.jdbc4.MySQLSyntaxErrorException;
import com.sun.rowset.CachedRowSetImpl;

public class ServerThread extends Thread {
	private static int counter = 0;
	private int id = ++counter;
	private Socket socket;
	private ObjectOutputStream out;
	private ObjectInputStream in;
	private Connection conn = BibliotecaJDBC.getConnection();
	private RandomPassword r = new RandomPassword();

	private Admin admin;
	private Cliente cliente;
	private Libri libri;
	private Prestiti prestiti;

	public ServerThread(Socket s) throws IOException, SQLException {
		socket = s;
		admin = new AdminImpl(conn);
		cliente = new ClienteImpl(conn);
		libri = new LibriImpl(conn);
		prestiti = new PrestitiImpl(conn);
		in = new ObjectInputStream(socket.getInputStream());
		out = new ObjectOutputStream(socket.getOutputStream());
		start();
		System.out.println("ServerThread id[" + id + "] avviato");
		System.out.println(socket);

	}

	@Override
	public void run() {
		try {
			String[] credenziali = null;
			while (true) {
				String str = (String) in.readObject();
				StringTokenizer st = new StringTokenizer(str, "_");
				String comando = st.nextToken();
				switch (comando) {
				case "generate":// per generare password
					out.writeObject(r.generate());
					out.flush();
					break;
				case "aggiungiCliente":
					cliente.aggiungiCliente(st.nextToken(), st.nextToken(),
							st.nextToken(), st.nextToken());
					break;
				case "ultimoIdCliente":
					int id = cliente.ultimoIdCliente();
					out.writeObject(id);
					out.flush();
					break;
				case "segnalaRegistrazioneCliente":
					try {
						EmailSend.segnalaRegistrazioneCliente(st.nextToken(),
								Integer.parseInt(st.nextToken()),
								st.nextToken(), st.nextToken(), st.nextToken());
					} catch (InvocationTargetException | InterruptedException e) {
					}
					break;
				case "restituisciLibro":
					cliente.aggiungiCliente(st.nextToken(), st.nextToken(),
							st.nextToken(), st.nextToken());
					out.writeObject("Libro Aggiunto");
					out.flush();
					break;
				case "getPassword":
					try {
						String ris = admin.getPassword(Integer.parseInt(st
								.nextToken()));
						out.writeObject(ris);
						out.flush();
					} catch (Exception c) {

						out.writeObject("null");
						out.flush();
					}
					break;
				case "getPassword2":
					try {
						String ris = cliente.getPassword(Integer.parseInt(st
								.nextToken()));
						out.writeObject(ris);
						out.flush();
					} catch (Exception c) {

						out.writeObject("null");
						out.flush();
					}
					break;
				case "hoIlLibro":
					boolean ris1 = libri.hoIlLibro(
							Integer.parseInt(st.nextToken()),
							Long.parseLong(st.nextToken()));
					out.writeObject(ris1);
					out.flush();
					break;
				case "modificaDataEffettiva":
					libri.modificaDataEffettiva(
							Integer.parseInt(st.nextToken()),
							Long.parseLong(st.nextToken()));
					break;
				case "incrementaCopie":
					libri.incrementaCopie(Long.parseLong(st.nextToken()),
							Integer.parseInt(st.nextToken()));
					break;
				case "decrementaCopie":
					cliente.decrementaCopie(Long.parseLong(st.nextToken()),
							Integer.parseInt(st.nextToken()));
					break;
				case "cercaCliente":
					String[] vStr = { "idCliente", "nome", "cognome", "email" };
					String[] vStr2 = { st.nextToken(), st.nextToken(),
							st.nextToken(), st.nextToken() };
					CachedRowSetImpl crs5 = new CachedRowSetImpl();
					ResultSet ris9 = cliente.cercaCliente(vStr2, vStr);
					crs5.populate(ris9);
					out.writeObject(crs5);
					out.flush();
					break;
				case "cercaLibro":
					String[] vStr3 = { "titolo", "autore", "genere",
							"casaEditrice" };
					String[] vStr4 = { st.nextToken(), st.nextToken(),
							st.nextToken(), st.nextToken() };
					CachedRowSetImpl crs6 = new CachedRowSetImpl();
					ResultSet ris10 = libri.cercaLibro(vStr4, vStr3);
					crs6.populate(ris10);
					out.writeObject(crs6);
					out.flush();
					break;
				case "storicoClienti":
					CachedRowSetImpl crs = new CachedRowSetImpl();
					String par1 = st.nextToken();
					ResultSet ris3 = cliente.storicoClienti(par1);
					crs.populate(ris3);
					out.writeObject(crs);
					out.flush();
					break;
				case "visualizzaPreferiti":
					CachedRowSetImpl crs1 = new CachedRowSetImpl();
					ResultSet ris4 = cliente.storicoClienti(Integer.parseInt(st
							.nextToken()));
					crs1.populate(ris4);
					out.writeObject(crs1);
					out.flush();
					break;
				case "clientiInScadenzaPrestito":
					CachedRowSetImpl crs2 = new CachedRowSetImpl();
					ResultSet ris5 = prestiti.clientiInScadenzaPrestito(Integer
							.parseInt(st.nextToken()));
					crs2.populate(ris5);
					out.writeObject(crs2);
					out.flush();
					break;
				case "getCredenziali":
					credenziali = cliente.getCredenziali(Integer.parseInt(st
							.nextToken()));
					break;
				case "getInfoLibro":
					CachedRowSetImpl crs3 = new CachedRowSetImpl();
					ResultSet ris7 = libri.getInfoLibro(Long.parseLong(st
							.nextToken()));
					crs3.populate(ris7);
					out.writeObject(crs3);
					out.flush();
					break;
				case "segnalaRestituzione":
					EmailSend.segnalaRestituzione(credenziali, st.nextToken(),
							Long.parseLong(st.nextToken()), st.nextToken());
					break;
				case "daRestituire":
					CachedRowSetImpl crs4 = new CachedRowSetImpl();
					ResultSet ris8 = cliente.daRestituire();
					crs4.populate(ris8);
					out.writeObject(crs4);
					out.flush();
					break;
				case "possoPrendereLibro":
					boolean ris11 = libri.possoPrendereLibro(
							Integer.parseInt(st.nextToken()),
							Long.parseLong(st.nextToken()));
					out.writeObject(ris11);
					out.flush();
					break;
				case "copieCliente":
					int ris12 = cliente.copieCliente(Integer.parseInt(st
							.nextToken()));
					out.writeObject(ris12);
					out.flush();
					break;
				case "copieLibri":
					int ris13 = libri
							.copieLibri(Long.parseLong(st.nextToken()));
					out.writeObject(ris13);
					out.flush();
					break;
				case "disponibile":
					boolean ris14 = libri.disponibile(Long.parseLong(st
							.nextToken()));
					out.writeObject(ris14);
					out.flush();
					break;
				case "decrementaCopie2":
					libri.decrementaCopie(Long.parseLong(st.nextToken()));
					break;
				case "incrementaCopie2":
					cliente.incrementaCopie(Integer.parseInt(st.nextToken()));
					break;
				case "aggiungiLibroStorico":
					libri.aggiungiLibroStorico(
							Integer.parseInt(st.nextToken()),
							Long.parseLong(st.nextToken()));
					break;
				case "getDataStimata":
					String ris15 = prestiti.getDataStimata(
							Long.parseLong(st.nextToken()),
							Integer.parseInt(st.nextToken()));
					out.writeObject(ris15);
					out.flush();
					break;
				case "esiste":
					boolean ris16 = libri
							.esiste(Long.parseLong(st.nextToken()));
					out.writeObject(ris16);
					out.flush();
					break;
				case "aggiornaCopie":
					libri.aggiornaCopie(Integer.parseInt(st.nextToken()),
							Long.parseLong(st.nextToken()));
					break;
				case "aggiungiLibro":
					libri.aggiungiLibro(Long.parseLong(st.nextToken()),
							st.nextToken(), st.nextToken(), st.nextToken(),
							st.nextToken(), Integer.parseInt(st.nextToken()),
							st.nextToken(), st.nextToken());
					break;
				case "segnalaConfermaPrestito":
					Long isbn = Long.parseLong(st.nextToken());
					EmailSend.segnalaConfermaPrestito(credenziali,
							libri.getInfoLibro(isbn), isbn, st.nextToken());
					break;
				case "mioStorico":
					String p1 = st.nextToken();
					String p2 = st.nextToken();
					ResultSet rs = cliente.mioStorico(p1, Integer.parseInt(p2));
					CachedRowSetImpl crs7 = new CachedRowSetImpl();
					crs7.populate(rs);
					out.writeObject(crs7);
					out.flush();
					break;
				case "setMail":
					cliente.setMail(st.nextToken(),
							Integer.parseInt(st.nextToken()));
					break;
				case "possoProlungarePrestito":
					ResultSet rs1 = prestiti.possoProlungarePrestito(
							Long.parseLong(st.nextToken()),
							Integer.parseInt(st.nextToken()));
					CachedRowSetImpl crs8 = new CachedRowSetImpl();
					crs8.populate(rs1);
					out.writeObject(crs8);
					out.flush();
					break;
				case "aggiornaPrestito":
					prestiti.aggiornaPrestito(Long.parseLong(st.nextToken()),
							Integer.parseInt(st.nextToken()));
					break;
				case "segnalaConfermaRinnovo":
					Long isbn1 = Long.parseLong(st.nextToken());
					EmailSend.segnalaConfermaRinnovo(credenziali,
							libri.getInfoLibro(isbn1), isbn1, st.nextToken());
					break;
				case "getGenerePreferito":
					String ris17 = cliente.getGenerePreferito(Integer
							.parseInt(st.nextToken()));
					out.writeObject(ris17);
					out.flush();
					break;
				case "consigliati":
					ResultSet rs2 = prestiti.consigliati(st.nextToken());
					CachedRowSetImpl crs9 = new CachedRowSetImpl();
					crs9.populate(rs2);
					out.writeObject(crs9);
					out.flush();
					break;
				case "getUltimiPresi":
					ResultSet ris18 = libri.getUltimiPresi();
					CachedRowSetImpl crs10 = new CachedRowSetImpl();
					crs10.populate(ris18);
					out.writeObject(crs10);
					out.flush();
					break;
				case "getUltimiArrivi":
					ResultSet ris19 = libri.getUltimiArrivi();
					CachedRowSetImpl crs11 = new CachedRowSetImpl();
					crs11.populate(ris19);
					out.writeObject(crs11);
					out.flush();
					break;
				case "esisteCliente":
					boolean ris20 = cliente.esisteCliente(Integer.parseInt(st
							.nextToken()));
					out.writeObject(ris20);
					out.flush();
					break;
				default:
					System.out.println("Errore " + comando);
					break;
				}
			}
		} catch (IOException e1) {
		} catch (ClassNotFoundException e2) {
		} catch (NumberFormatException e3) {
		} catch (MySQLSyntaxErrorException e) {
			try {
				out.writeObject("null");
				out.flush();
			} catch (IOException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		} catch (SQLException e4) {
			e4.printStackTrace();
			System.out.println(" Errore SQL");
		}
		try {
			System.out.println("ServerThread id[" + id
					+ "] ha chiuso la connesione");
			socket.close();
			counter--;
		} catch (IOException e) {
		}
	}
}
